home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Expert
/
Windows Expert.iso
/
windownt
/
help.zip
/
HELPCONV
/
MAIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-26
|
18KB
|
819 lines
#define LEN 256
#define ORDERED 1
#define SIMPLE 2
#define BULLET 3
#include <ctype.h>
#define TRUE 1
#define FALSE 0
char chdtText[LEN];
char chdthdText[LEN];
char chAppendBuffer[LEN * 4];
int append = 0;
int bExample = FALSE;
int num_styles = 0;
int ii_lineno = 1;
int ii_list_type = 0;
int ii_list_order = 1;
int bfirst = TRUE;
FILE *fp_rtf, *fp_ipf, *fp_err;
int isstring(ch)
char ch;
{
if ( isalnum(ch) || ((ch) == '_') || ((ch) == ' '))
return(TRUE);
else
return(FALSE);
}
//
// Main will take 1 or two arguements.
// With no arguements, the input file is assumed to be 'sample.ipf'
// The first arguement [if it exists] is the input file name.
// The second arguement, regardless of what it is, specifies
// 'debug mode' which prints tokens as they are read and intermixes
// this with the RTF output.
//
// The output is always out.rtf.
// stderr may be redirected. The default is the console.
//
main( argc, argv)
int argc;
char *argv[];
{
int ii;
int ii_token;
int ii_prev_token = 0;
char *input;
int debug = FALSE;
memset( chAppendBuffer, 0x00, LEN * 4);
ii = 0;
if (argc > 1)
input = argv[1];
else
input = "sample.ipf";
if (argc > 2)
debug = TRUE;
fp_ipf = freopen( input, "rt", stdin);
fp_rtf = freopen( "out.rtf", "w", stdout);
fp_err = stderr;
//
// Opening RTF commands. Note that :userdoc is ignored when found.
//
do_begin();
while (ii_token = yylex())
{
//
// Comments are eaten, thereby cleaning up debug output.
// The newline following the comment is eaten here as well.
//
if (ii_token == COMMENT)
{
if ((ii_token = yylex()) == NL)
{
ii_lineno++;
ii_token = yylex();
}
}
//
// Print that token if we are debugging.
//
if (debug)
debug_token( fp_rtf, ii_token);
//
// 'Append' mode is only entered when processing
// hypertext *outside* of a list item.
//
// We customize the parsing of hypertext and we need the
// entire string from :hpt thru :ehpt.
//
if ( append )
{
if ( ii_token == EHPT )
{
append = 0;
}
else
strcat( chAppendBuffer, yytext);
continue;
}
switch( ii_token)
{
case COMMENT: break;
// Note that the new line will not effect the text.
case COLON: fprintf( fp_rtf, ":\n", yytext); break;
// A newline is treated as whitespace in IPF, but not
// RTF. Insert that space!
case NTEXT: fprintf( fp_rtf, "%s \n", yytext); break;
// I keep track of newlines but don't use it yet.
// enhanced error reporting needs this.
case NL:
ii_lineno++;
if (bExample)
fprintf( fp_rtf, "\\par\n", yytext);
break;
case HDR: do_hdr(); break;
// Windows help doesn't differentiate between primary
// and secondary indexes.
case NDX1: do_ndx(); break;
case NDX2: do_ndx(); break;
case HPT: append = 1; break;
case EHPT: break;
case PARA: fprintf( fp_rtf, "\\par\n"); break;
case FNREF: do_hpt( 1); break;
case HDREF: do_hpt( 2); break;
case STYLE: do_style(); break;
case ESTYLE: do_estyle(); break;
// I do not honor margin requests at present.
// Partly because I don't know how to convert from
// IPF margin amounts to the correct figure in
// twips.
case MARGIN: break;
// I do not honor 'nt' commands, except to insert this
// string.
case NOTE: fprintf( fp_rtf, "Note: "); break;
case ENOTE: break;
// I can do nothing for examples, really.
case XMP: do_xmp(); break;
case EXMP: do_exmp(); break;
// I ignore the compact option, as well as lists-in-lists.
// This handles simple, ordered, and bullet lists.
case SL: do_list(); break;
case SLC: do_list(); break;
case DL: break;
case EDL:
case ESL:
case EPARML:
do_endlist();
break;
// Save the dthd text.
case DTHD:
while ((ii_token = yylex()) != NTEXT) ;
strcpy( chdthdText, yytext);
break;
// this requires a preceeding dthd.
case DDHD:
while ((ii_token = yylex()) != NTEXT) ;
do_ddhd();
break;
// Process a list item. This gets involved due to
// embedded styles and hypertext.
case LI: do_li(ii_list_type); break;
case DT: do_li(DT); break;
case DD: do_li(DD); break;
case PARML: break;
case PT: break;
case PD: break;
// runin is ignored.
case ARTWORK: do_art(); break;
case FN: do_fn(); break;
case EFN: fprintf( fp_rtf, "\\par\n"); break;
case USERDOC: break;
case EUSERDOC: fprintf( fp_rtf, "}"); return(0);
}
// historical, and it might be useful one day.
ii_prev_token = ii_token;
}
}
//
// Process an index command.
//
do_ndx()
{
char chName[LEN];
char chBuffer[LEN];
int ii = 0;
char ch;
char *pchsource;
char *pchdest;
pchsource = yytext;
//
// Looking for the ending '.' of the tag. This position differs between
// primary and secondary indexes.
//
while ( *pchsource++ != '.') ;
pchdest = chBuffer;
while (isstring(ch = *pchsource++))
{
*pchdest++ = ch;
}
*pchdest = 0x00;
fprintf( fp_rtf, "K{\\footnote %s}\n", chBuffer);
}
//
// What type of list is it?
//
do_list()
{
switch( yytext[1])
{
case 'u':
ii_list_type = BULLET;
break;
case 'o':
ii_list_type = ORDERED;
break;
case 's':
default:
ii_list_type = SIMPLE;
}
}
#define LIST_FORMAT() \
fprintf( fp_rtf, "\\par\n\\pard\\fi-240\\li300\\tx300\\ri120\\sb60\n")
//
// Process a nice, harry header line.
//
do_hdr()
{
char chName[LEN];
char chBuffer[LEN];
int ii = 0;
char ch;
char *pchsource;
char *pchdest;
// Obtain the ID of the header.
get_id( chName, "Header", yytext);
// This assumes the name of the header is on the same line
// as the :h tag.
pchsource = yytext;
while ( *pchsource++ != '.') ;
pchdest = chBuffer;
while (isstring(ch = *pchsource++))
{
*pchdest++ = ch;
}
*pchdest = 0x00;
if (!bfirst)
{
fprintf( fp_rtf, "\\page\n");
}
else
bfirst = FALSE;
fprintf( fp_rtf, "\\pard\\sb120\\f2\\fs20\\li60\\ri60\n");
fprintf( fp_rtf, "${\\footnote %s}\n", chBuffer);
// fprintf( fp_rtf, "K{\\footnote %s}\n", chBuffer);
fprintf( fp_rtf, "#{\\footnote %s}\n", chName);
}
//
// Handle hypertext outside of a list item.
//
do_hpt( flag)
int flag;
{
char chBuffer[LEN];
get_id( chBuffer, "Hypertext", yytext);
fprintf( fp_rtf, "{\\ul");
if ( flag == 2)
fprintf( fp_rtf, "db ");
else
fprintf( fp_rtf, " ");
fprintf( fp_rtf, "%s}{\\v %s} \n", chAppendBuffer, chBuffer);
memset( chAppendBuffer, 0x00, LEN * 4);
}
#if 0
get_name(pchName, pchError)
char *pchName;
char *pchError;
{
int ii = 0;
char ch;
while ( yytext[ii] && yytext[ii] != '=' ) ii++;
if ( yytext[ii] != '=')
{
fprintf(fp_err, "Error parseing %s\n", pchError);
}
ii++;
while ( ch = yytext[ii] )
{
if ( isalnum(ch))
{
*pchName++ = ch;
}
ii++;
}
*pchName = 0x00;
}
#endif
//
// Place a ID name [precedded by an '=']
// in pchName from the string pchSource
// and write an error message based on pchError if you don't find it.
//
get_id(pchName, pchError, pchSource)
char *pchName;
char *pchError;
char *pchSource;
{
int ii = 0;
char ch;
while ( *pchSource && *pchSource != '=' ) pchSource++;
if ( *pchSource != '=')
{
//
// List processing now has some error recovery, and
// a way of handling this error so it doesn't want the
// error message in that case.
//
if (pchError)
fprintf(fp_err, "Error parseing %s\n", pchError);
return(-1);
}
pchSource++;
while ( isalnum(ch = *pchSource) || *pchSource == '_')
{
*pchName++ = ch;
pchSource++;
}
*pchName = 0x00;
return(0);
}
// do a footnote.
do_fn()
{
char chBuffer[256];
char ch;
get_id( chBuffer, "Footnote", yytext);
fprintf( fp_rtf, "\\page\n\\pard\\sb120\\f2\\fs20\\li60\\ri60\n");
fprintf( fp_rtf, "#{\\footnote %s}", chBuffer);
}
do_endlist()
{
ii_list_order = 1;
ii_list_type = 0;
fprintf( fp_rtf, "\\par\n\\pard\\li60\\ri60\\sb120\n");
}
//
// Search the RTF file for MS_MS to locate example code.
//
do_xmp()
{
bExample = TRUE;
fprintf( fp_rtf, "\\sb0\\par\n\\pard\\f5\\li300\\ri120\\keep\n");
fprintf( fp_rtf, "MS_MS Example follows:\\par\n");
}
do_exmp()
{
bExample = FALSE;
fprintf( fp_rtf, "\\keep\\par\\pard");
}
// unwind those styles!
do_estyle()
{
while ( num_styles > 0)
{
num_styles--;
fprintf( fp_rtf, "}");
}
fprintf( fp_rtf, "\n");
}
// establish style type and begin it appropriately
do_style()
{
char ch;
int ii_style;
ii_style = yytext[3] - '0';
switch (ii_style)
{
case 1:
num_styles += 1;
fprintf( fp_rtf, "{\\i ");
break;
case 2:
num_styles += 1;
fprintf( fp_rtf, "{\\b ");
break;
case 3:
num_styles += 2;
fprintf( fp_rtf, "{\\b {\\i ");
break;
case 5:
num_styles = +1;
fprintf( fp_rtf, "{\\ul ");
break;
default:
fprintf( fp_err, "Unknown Style %d\n", ii_style);
}
}
do_ddhd()
{
fprintf( fp_rtf, "\\par\\pard\\sb120\\fi-1568\\li1628\\tx1628");
fprintf( fp_rtf, "\\ri120\\brdrb\\brdrs\n");
fprintf( fp_rtf, "{%s \\tab %s}\n", chdthdText, yytext);
}
do_art( )
{
int ii = 0;
int jj = 6;
char chBuffer[256];
char ch;
int bPeriod = FALSE;
while ( yytext[ii] && yytext[ii] != '=' ) ii++;
if ( yytext[ii] != '=')
{
fprintf(fp_err, "Error parseing Artwork\n");
}
ii++;
sprintf( chBuffer, "\\{bmc ");
while ( ch = yytext[ii] )
{
if (ch == '.')
if (!bPeriod)
{
chBuffer[jj++] = ch;
bPeriod = TRUE;
}
if ( isalpha(ch) )
{
chBuffer[jj++] = ch;
}
if (ch == ' ')
{
yytext[ii] = 0x00;
}
else
ii++;
}
chBuffer[jj] = 0x00;
fprintf( fp_rtf, "%s\\}\n", chBuffer);
}
do_begin()
{
fprintf( fp_rtf, "{\\rtf1\\ansi\n");
fprintf( fp_rtf, "{\\fonttbl\n");
fprintf( fp_rtf, "{\\f0\\froman Tms Rmn; }\n");
fprintf( fp_rtf, "{\\f1\\fdecor Courier; }\n");
fprintf( fp_rtf, "{\\f2\\fswiss Helv; }\n");
fprintf( fp_rtf, "{\\f3\\fdecor ZapfDingbats; }\n");
fprintf( fp_rtf, "{\\f4\\fdecor Symbol; }\n");
fprintf( fp_rtf, "{\\f5\\fmodern Courier; }\n");
fprintf( fp_rtf, "}\n");
fprintf( fp_rtf, "{\\colortbl;\n");
fprintf( fp_rtf, "\\red0\\green0\\blue0;\\red255\\green0\\blue0;");
fprintf( fp_rtf, "\\red0\\green128\\blue0;\\red0\\green0\\blue255;");
fprintf( fp_rtf, "}\n");
}
#ifdef DEBUG
#include "dbgtok.h"
#endif
char yytmp[YYLMAX];
//
// The situation: while processing a list item I discover that
// it is incomplete, and some formatting is on the next line.
//
// I need to get the next line, regardless of its token value,
// and append to my current text.
//
// This is designed to do that.
//
int append_token(ii_nl)
int ii_nl;
{
int ii_new = 0;
yytmp[0] = 0x00;
strcpy( yytmp, yytext);
while (ii_nl)
{
ii_new = yylex();
if (ii_new != NL)
strcat( yytmp, yytext);
else
{
strcat( yytmp, " ");
ii_nl--;
ii_lineno++;
}
}
strcpy( yytext, yytmp);
return(ii_new);
}
//
// List items: Complex parsing!
//
do_li(list_type)
int list_type;
{
char *pchsource = yytext + 4;
char chListText[LEN];
char *pchList = chListText;
char chRefText[LEN];
char *pchRef = chRefText;
char chHyperText[LEN];
char *pchHyper = chHyperText;
char chHyperLinkBuffer[LEN];
char chBuffer[LEN];
char ch;
int bHyper = FALSE;
int bRef = FALSE;
int ii_type = 0;
memset( chListText, 0x00, LEN);
*pchRef = 0x00;
*pchHyper = 0x00;
// Parse the input string into the output list buffer.
while ( ch = *pchsource++)
{
// Copy if it isn't a tag
if (ch != ':' )
{
*pchList++ = ch;
}
// a hypertext reference.
else if ( ( strncmp( pchsource, "hdref", 5) == 0)
|| ( strncmp( pchsource, "fnref", 5) == 0) )
{
if (bHyper == FALSE)
{
fprintf( fp_err, "No Hypertext!");
*pchHyper = 0x00;
}
if (*pchsource == 'h')
ii_type = 1;
//
// Find the ID. If you don't find it the first time,
// go to next line to find it.
//
if (get_id( chRefText, NULL, pchsource))
{
append_token(2);
if (get_id( chRefText, "Embedded Reference", pchsource))
exit(-1);
}
strcpy( chBuffer, "{\\ul");
if (ii_type == 1)
strcat( chBuffer, "db");
//
// This is a little extra fancy since I am accumulating
// a text string in chListText instead of doing direct
// RTF output.
//
sprintf( chHyperLinkBuffer, "%s %s}{\\v %s}",
chBuffer, chHyperText, chRefText);
strcat( chListText, chHyperLinkBuffer);
pchList = chListText + strlen( chListText);
chHyperText[0] = 0x00;
chHyperLinkBuffer[0] = 0x00;
pchHyper = chHyperText;
bHyper = FALSE;
// copy till we find the ending period.
do
{
ch = *pchsource++;
} while (ch && ch != '.');
if ( ch == 0x00)
pchsource--;
}
// end style
else if (strncmp( pchsource, "ehp", 3) == 0)
{
while ( num_styles > 0)
{
num_styles--;
*pchList++ = '}';
}
pchsource += 5;
}
// Begin a style
else if ( *pchsource == 'h' &&
*(pchsource + 1) == 'p' &&
isdigit(*(pchsource + 2)))
{
switch ( *(pchsource + 2) )
{
case '1':
num_styles += 1;
strcat( pchList - 1, "{\\i ");
pchList += 4;
break;
case '2':
num_styles += 1;
strcat( pchList - 1, "{\\b ");
pchList += 4;
break;
case '3':
num_styles += 2;
strcat( pchList - 1, "{\\b {\\i ");
pchList += 8;
break;
case '5':
num_styles += 1;
strcat( pchList - 1, "{\\ul ");
pchList += 5;
break;
default:
fprintf( fp_err, "Unknown Style in List\n");
}
pchsource += 4;
}
// Begin hypertext
else if ( strncmp( pchsource, "hpt.", 4) == 0)
{
bHyper = TRUE;
pchsource += 4;
do
{
ch = *pchsource++;
if (ch != ':')
*pchHyper++ = ch;
else if ( strncmp( pchsource, "ehpt.", 5) == 0)
{
pchsource += 5;
*pchHyper = 0x00;
ch = 0x00;
}
else
{
fprintf( fp_err, "Unexpected Token", pchsource);
*pchHyper = 0x00;
ch = 0x00;
}
} while (ch != 0x00);
}
}
// Now that we have a complex output buffer, format it
// properly for the type of list we are processing.
switch (list_type)
{
case BULLET:
LIST_FORMAT();
fprintf( fp_rtf, "\\{bmc bullet.bmp\\}\n\\tab\n%s\n",
chListText);
break;
case ORDERED:
fprintf( fp_rtf, "\\par\n");
LIST_FORMAT();
fprintf( fp_rtf, "%d\n\\tab\n", ii_list_order++);
fprintf( fp_rtf, "%s\n", chListText);
break;
case SIMPLE:
fprintf( fp_rtf, "\\par\n");
LIST_FORMAT();
fprintf( fp_rtf, "%s\n", chListText);
break;
case DD:
fprintf( fp_rtf, "\\par\n\\pard\\fi-1568\\li1628\\tx1628");
fprintf( fp_rtf, "\\ri120\\sb60\n{%s}\n\\tab\n%s \n",
chdtText, chListText);
break;
case DT:
strcpy( chdtText, chListText);
break;
}
}
// A debug print routine.
debug_token( fp, ii)
FILE *fp;
int ii;
{
switch( ii)
{
case NL:
case COMMENT:
break;
case COLON:
case NTEXT:
case HDR:
case NDX1:
case NDX2:
case HPT:
case EHPT:
case PARA:
case FNREF:
case HDREF:
case STYLE:
case ESTYLE:
case MARGIN:
case NOTE:
case ENOTE:
case XMP:
case EXMP:
case LI:
case SL:
case SLC:
case DL:
case EDL:
case ESL:
case EPARML:
case DTHD:
case DDHD:
case DT:
case DD:
case PARML:
case PT:
case PD:
case ARTWORK:
case FN:
case EFN:
case USERDOC:
case EUSERDOC:
fprintf( fp, "##%s {{%s}}\n", pch_token_string[ii], yytext);
break;
default:
break;
}
}